package com.com.gmail.at.vssabinin.client;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.ByteBuffer;

import javax.swing.JOptionPane;

public class Client {
	private InetAddress hostAddress; 
	private int port;

	private Socket clientSocket = null;
	
	private Protocol protocol = new Protocol();
	
	private InputStream input = null;
	private OutputStream output = null;
	
	public <T extends Serializable> void sendThroughProtocol (String message, T object) {
		this.write(this.protocol.createMessage(this.protocol.new Message(message, object)));
	}
	
	public Protocol.Message readThroughProtocol() {
		try {
				byte[] data = this.read();
				return this.protocol.decodeMessage(ByteBuffer.wrap(data));
			} catch (Exception e) {
				return null;
			}		
	}
	
	public boolean startClient(InetAddress host, int givenPort) {
		this.hostAddress = host;
		this.port = givenPort;
		boolean done = false;
		while (!done) {
			try {
	        	this.clientSocket = new Socket(this.hostAddress, this.port);
	        	this.clientSocket.setSoTimeout(5000);
				this.output = this.clientSocket.getOutputStream();
				this.input = this.clientSocket.getInputStream();
				return true;
			} catch (IOException e) {
				int selection = JOptionPane.showConfirmDialog(null, "Server doesn't response, try to reconnect?", 
						"Warning", JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE);
		    	if (selection == JOptionPane.YES_OPTION) {
		    		Main.mainInstance.client.reconnect(Main.mainInstance.client);
		    	} else {
		    		done = true;
		    		Main.mainInstance.exit();
				}
		    }
		}
		return false;
	}
	
	public void stopClient() {
		try {
			if (input != null) {
				this.input.close();
			}
			if (output != null) {
				this.input.close();
			}
			if (clientSocket != null) {
				this.clientSocket.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void write (byte[] data) {
		boolean done = false;
		while (!done) {
			try {
				this.output.write(data);
				done = true;
			} catch (IOException e) {
				int selection = JOptionPane.showConfirmDialog(null, "Server doesn't response, try to reconnect?", 
						"Warning", JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE);
		    	if (selection == JOptionPane.YES_OPTION) {
		    		Main.mainInstance.client.reconnect(Main.mainInstance.client);
		    	} else {
		    		done = true;
		    		Main.mainInstance.exit();
				}
		    }
		}		 
	}
	
	private byte[] read () {
		byte[] data = new byte[9999];
		BufferedInputStream bin = null;
		try {
			bin = new BufferedInputStream(this.input);
			bin.read(data);
		} catch (IOException e) {
			int selection = JOptionPane.showConfirmDialog(null, "Server doesn't response, try to reconnect?", 
					"Warning", JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE);
	    	if (selection == JOptionPane.YES_OPTION) {
	    		Main.mainInstance.client.reconnect(Main.mainInstance.client);
	    		return null;
	    	} else {
	    		Main.mainInstance.exit();
			}	
		}
		return data;
	}
	
	private void reconnect (Client client) {
		try {
			if (clientSocket != null) {
				client.clientSocket.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		client.startClient(Main.mainInstance.adress, 1015);
		try {
			this.input = client.clientSocket.getInputStream();
			this.output = client.clientSocket.getOutputStream();
		} catch (IOException e) {
			
		}
		if (Main.mainInstance.passenger != null) {
			Main.mainInstance.client.sendThroughProtocol("login", Main.mainInstance.passenger);
			Protocol.Message message = Main.mainInstance.client.readThroughProtocol();
			if (message.getType().equals("ok")) {
				 JOptionPane.showMessageDialog(null, "You have reconnected to the server!");
		    } else if (message.getType().equals("no")) {
		        JOptionPane.showMessageDialog(null, "Some error ocurs, during reconnection, try again later!");
		    }       
		} 
	}
}
